package com.atguigu3.dao;

import com.utils.JDBCUtilsJiuBan;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 封装了针对于数据表的通用操作
 * BaseDao
 *  DAO: date(base) access object
 * @auther user
 * @date 2021/12/9 - 6:21
 */
public abstract class BaseDao<T> {

    private Class<T> clazz = null;

/*
    构造器中赋值
    public BaseDao(){

    }*/
//静态代码块
{
    //当前对象的带泛型的父类（获取当前BaseDao的子类继承的父类中的泛型）
    //this 这里指子类，子类继承父类，调用的类方法
    Type genericSuperclass = this.getClass().getGenericSuperclass();
    ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
    Type[] typeArguments = parameterizedType.getActualTypeArguments();//获取了父类的泛型参数
    clazz = (Class<T>) typeArguments[0];//泛型的第一个参数
}

    //通用更新操作 -----Version 2.0 -----考虑事务
    public int update(Connection connection, String sql, Object ...args) {
        PreparedStatement preparedStatement = null;
        try {
            //1 获取连接
            //2 预编译sql,返回preparedStatment实例
            preparedStatement = connection.prepareStatement(sql);
            //3 填充占位符
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i+1,args[i]);
            }
            //4 执行
            return preparedStatement.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            JDBCUtilsJiuBan.closeResource(null,preparedStatement);
        }
        return 0;
    }

    //针对于不同表的通用查询操作，返货一条记录----Version 2.0 考虑事务
    public T getInstance(Connection connection,String sql,Object ...args) {
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //1 获取连接
            //2 预编译sql,返回preparedStatment实例
            preparedStatement = connection.prepareStatement(sql);
            //3 填充占位符
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i+1,args[i]);
            }
            //4 执行，返回ResultSet结果集
            resultSet = preparedStatement.executeQuery();
            //5 处理结果集
            //获取元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取总列数
            int columnCount = metaData.getColumnCount();
            if (resultSet.next()){
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    //获取列别名
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    //获取列值
                    Object columnValue = resultSet.getObject(i + 1);
                    //通过反射，将clumnValue存储到t对象的columLabel属性中
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t,columnValue);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtilsJiuBan.closeResource(null,preparedStatement,resultSet);
        }
        return null;
    }
    //针对于不同表的通用查询操作，返回list-------Version 2.0 考虑事务
    public List<T> getForList(Connection connection, String sql, Object ...args){
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //1 获取连接
            //2 预编译sql,返回perparedStatment实例
            preparedStatement = connection.prepareStatement(sql);
            //3 填充占位符
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i+1,args[i]);
            }
            //4 执行，返回ResultSet结果集
            resultSet = preparedStatement.executeQuery();
            //5 处理结果集
            //5.1 获取元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            //5.2 获取总列数
            int columnCount = metaData.getColumnCount();
            //5.3 创建结果集
            ArrayList<T> arrayList = new ArrayList<T>();
            while (resultSet.next()){
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    //5.4 获取字段别名
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    //5.5 获取字段值
                    Object columnValue = resultSet.getObject(i + 1);
                    //5.6 通过反射，将columnValue存储到t对象的columnLavel属性中
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t,columnValue);
                }
                arrayList.add(t);
            }
            return arrayList;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            JDBCUtilsJiuBan.closeResource(null,preparedStatement,resultSet);
        }
        return null;
    }
    //特殊情况 组函数 select count(*) from table
    public <E>E getValue(Connection connection, String sql, Object ...args) {
        PreparedStatement preparedStatement = null;
        try {
            //1 获取链接
            //2 预编译sql,返回preparedStatment实例
            preparedStatement = connection.prepareStatement(sql);
            //3 填充占位符
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i+1,args[i]);
            }
            //4 执行,返回ResultSet结果集
            ResultSet resultSet = preparedStatement.executeQuery();
            //5 处理结果集
            if (resultSet.next()){
               return(E) resultSet.getObject(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            JDBCUtilsJiuBan.closeResource(null,preparedStatement);
        }
        return null;
    }
}
